home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 3 / Info_Mac_1994-01.iso / Development / Source / TCL Terminalpane 1.0 / CTerminalPane.cp next >
Text File  |  1993-08-16  |  14KB  |  641 lines

  1. /*
  2. ** CTerminalPane.h
  3. **
  4. **    Eric’s standard libraries
  5. **    Terminal display pane
  6. **
  7. **    Copyright © 1993, FrostByte Design / Eric Scouten
  8. **    Portions copyright © 1990 Symantec Corporation. All rights reserved.
  9. */
  10.  
  11.  
  12. #include "CTerminalPane.h"
  13.  
  14. #include <Events.h>
  15. #include <LongCoordinates.h>
  16. #include <LongQD.h>
  17.  
  18.  
  19. /* global TCL objects */
  20.  
  21. extern CBureaucrat *gGopher;
  22.  
  23.  
  24. /*______________________________________________________________________
  25. **
  26. ** ITerminalPane
  27. **
  28. **    Initialize the pane. Nothing special here. Parameters are all the same as
  29. **    for CPanorama::IPanorama.
  30. **
  31. */
  32.  
  33. void CTerminalPane::ITerminalPane (CView *anEnclosure, CBureaucrat *aSupervisor,
  34.                             short aWidth, short aHeight, short aHEncl, short aVEncl,
  35.                             SizingOption aHSizing, SizingOption aVSizing)
  36.  
  37. {
  38.     LongRect theBounds;
  39.  
  40.     CPanorama::IPanorama(anEnclosure, aSupervisor, aWidth, aHeight, aHEncl, aVEncl,
  41.                         aHSizing, aVSizing);
  42.     
  43.     SetLongRect(&theBounds, 0, 0, sizeX, sizeY);
  44.     SetBounds(&theBounds);
  45.     SetCanBeGopher(TRUE);
  46.     SetWantsClicks(TRUE);
  47.     
  48.     if (member(itsEnclosure, CScrollPane))
  49.         ((CScrollPane *) itsEnclosure)->SetSteps(pixelsX, pixelsY);
  50.     
  51.     blinkCursor = FALSE;
  52.     cursorVis = TRUE;
  53.     lastCursorCol = lastCursorLine = 0;
  54.     lastCursorTick = 0L;
  55.     DoClearScreen();
  56. }
  57.  
  58.  
  59. /*______________________________________________________________________
  60. **
  61. ** BecomeGopher
  62. **
  63. **    Become the gopher (or leave gopher status). All our routine does is force a refresh
  64. **    of the cursor.
  65. **
  66. **        fBecoming (Boolean):        TRUE if becoming gopher
  67. **
  68. **        return (Boolean):        TRUE if successful in changing status
  69. **
  70. */
  71.  
  72. Boolean CTerminalPane::BecomeGopher (Boolean fBecoming)
  73.  
  74. {
  75.     if (!fBecoming)
  76.         cursorVis = TRUE;
  77.     InvalCharRect(theColumn, theLine, theColumn, theLine);
  78.     return CPanorama::BecomeGopher(fBecoming);
  79. }
  80.  
  81.  
  82. /*______________________________________________________________________
  83. **
  84. ** CalcCharRect (protected method)
  85. **
  86. **    Calculate the screen coordinates for a specified rectangle of
  87. **    character coordinates. Upper left corner is (0,0).
  88. **
  89. **        left (short):            left edge of char rectangle
  90. **        top (short):            top edge
  91. **        right (short):            right edge, inclusize
  92. **        bottom (short):            bottom edge, inclusive
  93. **        theRect (LongRect *):    coordinates returned to this rectangle
  94. **
  95. */
  96.  
  97. void CTerminalPane::CalcCharRect (short left, short top, short right, short bottom,
  98.                             LongRect *theRect)
  99.  
  100. {
  101.     SetLongRect(theRect,
  102.                 (long) left * pixelsX + offsetX,
  103.                 (long) top * pixelsY + offsetY,
  104.                 (long) (right+1) * pixelsX + offsetX,
  105.                 (long) (bottom+1) * pixelsY + offsetY);
  106. }
  107.  
  108.  
  109. /*______________________________________________________________________
  110. **
  111. ** ClearToEOL (protected method)
  112. **
  113. **    Clear from the indicated point to the end of a line. Upper left
  114. **    corner is (0,0).
  115. **
  116. **        col (short):    first column in line to clear
  117. **        line (short):    line to be cleared
  118. **
  119. */
  120.  
  121. void CTerminalPane::ClearToEOL (short col, short line)
  122.  
  123. {
  124.     InvalCharRect(col, line, maxX-1, line);
  125.     while (col < maxX)
  126.         theScreen[line][col++] = ' ';
  127. }
  128.  
  129.  
  130. /*______________________________________________________________________
  131. **
  132. ** ClearToEOS (protected method)
  133. **
  134. **    Clear from the indicated point to the end of the screen. Upper left
  135. **    corner is (0,0).
  136. **
  137. **        col (short):    first column in first line to clear
  138. **        line (short):    first line to be cleared
  139. **
  140. */
  141.  
  142. void CTerminalPane::ClearToEOS (short col, short line)
  143.  
  144. {
  145.     while (line < maxY) {
  146.         ClearToEOL(col, line++);
  147.         col = 0;
  148.     }
  149. }
  150.  
  151.  
  152. /*______________________________________________________________________
  153. **
  154. ** CursorMoved
  155. **
  156. **    Update the blinking cursor block.
  157. **
  158. */
  159.  
  160. void CTerminalPane::CursorMoved (void)
  161.  
  162. {
  163.     cursorVis = TRUE;
  164.     lastCursorTick = Ticks;
  165.     InvalCharRect(lastCursorCol, lastCursorLine, lastCursorCol, lastCursorLine);
  166.     InvalCharRect(theColumn, theLine, theColumn, theLine);
  167.     lastCursorCol = theColumn;
  168.     lastCursorLine = theLine;
  169. }
  170.  
  171.  
  172. /*______________________________________________________________________
  173. **
  174. ** Dawdle
  175. **
  176. **    Blink the cursor if necessary. Cursor blinks at the user-defined rate for insertion point
  177. **    blinking.
  178. **
  179. **        maxSleep (long *):    maximum sleep value, updated if necessary
  180. **
  181. */
  182.  
  183. void CTerminalPane::Dawdle (long *maxSleep)
  184.  
  185. {
  186.     CPanorama::Dawdle(maxSleep);
  187.     if (blinkCursor) {
  188.         *maxSleep = Min(*maxSleep, GetCaretTime());
  189.         if (Ticks >= lastCursorTick + GetCaretTime()) {
  190.             cursorVis = !cursorVis;
  191.             lastCursorTick = Ticks;
  192.             InvalCharRect(theColumn, theLine, theColumn, theLine);
  193.         }
  194.     }
  195. }
  196.  
  197.  
  198. /*______________________________________________________________________
  199. **
  200. ** DoClearScreen
  201. **
  202. **    Clear the screen and move the cursor to (0,0).
  203. **
  204. */
  205.  
  206. void CTerminalPane::DoClearScreen (void)
  207.  
  208. {
  209.     register short x, y;
  210.     
  211.     theLine = theColumn = 0;
  212.     CursorMoved();
  213.  
  214.     for (y = 0; y < maxY; ++y)
  215.         for (x = 0; x < maxX; ++x)
  216.             theScreen[y][x] = ' ';
  217.     Refresh();
  218. }
  219.  
  220.  
  221. /*______________________________________________________________________
  222. **
  223. ** DoEraseChar
  224. **
  225. **    Erase one character from screen (backspace).
  226. **
  227. */
  228.  
  229. void CTerminalPane::DoEraseChar (void)
  230.  
  231. {
  232.     register short x;
  233.     
  234.     if (theColumn > 0) {
  235.         theColumn--;
  236.         for (x = theColumn; x < maxX-1; x++)
  237.             theScreen[theLine][x] = theScreen[theLine][x+1];
  238.         theScreen[theLine][maxX-1] = ' ';
  239.         InvalCharRect(theColumn, theLine, maxX-1, theLine);
  240.         CursorMoved();
  241.     }
  242. }
  243.  
  244.  
  245. /*______________________________________________________________________
  246. **
  247. ** DoEraseLine
  248. **
  249. **    Move the cursor back to beginning of line & erase line.
  250. **
  251. */
  252.  
  253. void CTerminalPane::DoEraseLine (void)
  254.  
  255. {
  256.     theColumn = 0;
  257.     ClearToEOL(0, theLine);
  258.     CursorMoved();
  259. }
  260.  
  261.  
  262. /*______________________________________________________________________
  263. **
  264. ** DoWriteBfr
  265. **
  266. **    Write the contents of a text buffer to the terminal. This method
  267. **    merely dishes out the characters to the DoWriteChar method.
  268. **
  269. **        theStr (char *):    the buffer to write
  270. **        theSize (short):    size of the data buffer
  271. **
  272. */
  273.  
  274. void CTerminalPane::DoWriteBfr (char *theStr, short theSize)
  275.  
  276. {
  277.     while (theSize--)
  278.         DoWriteChar(*(theStr++));
  279. }
  280.  
  281.  
  282. /*______________________________________________________________________
  283. **
  284. ** DoWriteChar
  285. **
  286. **    Write a character to the terminal. This method handles *basic* terminal emulation.
  287. **    To provide more sophisticated emulation, override this method.
  288. **
  289. **        theChar (char):        the character to write
  290. **
  291. */
  292.  
  293. void CTerminalPane::DoWriteChar (char theChar)
  294.  
  295. {
  296.     /* parse a few control characters */
  297.     
  298.     switch (theChar) {
  299.  
  300.         case charNUL:
  301.             break;
  302.  
  303.         case charBEL:
  304.             SysBeep(0);
  305.             break;
  306.  
  307.         case charBS:
  308.             if (theColumn > 0)
  309.                 theColumn--;
  310.             CursorMoved();
  311.             break;
  312.  
  313.         case charHT:
  314.             theColumn = ((short) ((theColumn + 7) / 8)) * 8;
  315.             if (theColumn >= maxX)
  316.                 theColumn = maxX-1;
  317.             CursorMoved();
  318.             break;
  319.             
  320.         case charLF:
  321.             if (theLine < maxY-1)
  322.                 theLine++;
  323.             else
  324.                 ScrollTerm();
  325.             CursorMoved();
  326.             ScrollToSelection();
  327.             break;
  328.             
  329.         case charFF:
  330.             DoClearScreen();
  331.             ScrollToSelection();
  332.             break;
  333.             
  334.         case charCR:
  335.             theColumn = 0;
  336.             CursorMoved();
  337.             break;
  338.         
  339.         default:
  340.             theScreen[theLine][theColumn] = theChar;
  341.             InvalCharRect(theColumn, theLine, theColumn, theLine);
  342.             if (theColumn < maxX)
  343.                 theColumn++;
  344.             CursorMoved();
  345.     }
  346. }
  347.  
  348.  
  349. /*______________________________________________________________________
  350. **
  351. ** DoWriteCharNum
  352. **
  353. **    Write a character number to the terminal. Provided as a debugging routine
  354. **    by other classes. The number is bracketed by the two characters indicated, i.e.
  355. **    if you call ::DoWriteCharNum('!', '[', ']'), you get [33] written to the terminal.
  356. **
  357. **        theChar (char):        the character number to write
  358. **        leftBracket (char):    prefix to character number
  359. **        rightBracket(char):    suffix to character number
  360. **
  361. */
  362.  
  363. void CTerminalPane::DoWriteCharNum (char theChar, char leftBracket, char rightBracket)
  364.  
  365. {
  366.     Str255 cNumber;
  367.  
  368.     DoWriteChar(leftBracket);
  369.  
  370.     NumToString((short) theChar, cNumber);
  371.     cNumber[cNumber[0]+1] = '\0';
  372.     DoWriteStr((char *) (&cNumber)+1);
  373.     
  374.     DoWriteChar(rightBracket);
  375. }
  376.  
  377.  
  378. /*______________________________________________________________________
  379. **
  380. ** DoWriteStr
  381. **
  382. **    Write a string to the terminal. This method is optimized to handle text strings. It skips
  383. **    any control characters and sends them directly to DoWriteChar.
  384. **
  385. **        theStr (char *):    the string to write (C string)
  386. **
  387. */
  388.  
  389. void CTerminalPane::DoWriteStr (char *theStr)
  390.  
  391. {
  392.     short leftCol;
  393.     
  394.     /* optimize for text characters */
  395.     
  396.     while (*theStr) {
  397.         if (*theStr >= ' ') {
  398.             leftCol = theColumn;
  399.             while (*theStr >= ' ') {
  400.                 theScreen[theLine][theColumn] = *(theStr++);
  401.                 if (theColumn < maxX)
  402.                     theColumn++;
  403.             }
  404.             InvalCharRect(leftCol, theLine, theColumn, theLine);
  405.             CursorMoved();
  406.         }
  407.         if (*theStr)
  408.             DoWriteChar(*(theStr++));
  409.     }
  410. }
  411.  
  412.  
  413. /*______________________________________________________________________
  414. **
  415. ** Draw
  416. **
  417. **    Draw characters from the theScreen array onto the real screen.
  418. **
  419. **        area (Rect *):    area to be redrawn (in frame coordinates)
  420. **
  421. */
  422.  
  423. void CTerminalPane::Draw (Rect *area)
  424.  
  425. {
  426.     short    left, top, right, bottom;        /* char coordinatates of draw region */
  427.     short    dLine;                    /* where to draw now */
  428.     LongRect    theLongArea;                /* frame coordinates of region */
  429.     LongPt    theLongPt;
  430.     Point        thePoint;
  431.     
  432.     /* figure draw region */
  433.     
  434.     QDToFrameR(area, &theLongArea);
  435.     left = (theLongArea.left - offsetX) / pixelsX;
  436.     right = (theLongArea.right -offsetX + 1) / pixelsX;
  437.     top = (theLongArea.top - offsetY) / pixelsY;
  438.     bottom = (theLongArea.bottom -offsetY + 1) / pixelsY;
  439.     
  440.     /* do range checking */
  441.     
  442.     left = Max(left, 0);
  443.     top = Max(top, 0);
  444.     right = Min(right, maxX-1);
  445.     bottom = Min(bottom, maxY-1);
  446.     
  447.     /* hard-wire for Monaco 9: Mom, don’t look at this code! */
  448.     
  449.     TextFont(4);
  450.     TextFace(0);
  451.     TextSize(9);
  452.     
  453.     /* draw the stuff */
  454.     
  455.     if (left <= right) {
  456.         HLock((Handle) this);
  457.         dLine = top;
  458.         while (dLine <= bottom) {
  459.             SetLongPt(&theLongPt, left * pixelsX, dLine * pixelsY);
  460.             FrameToQD(&theLongPt, &thePoint);
  461.             MoveTo(thePoint.h + offsetX, thePoint.v + offsetY + pixelsY-2);
  462.             DrawText(&theScreen[dLine][left], 0, right-left+1);
  463.             dLine++;
  464.         }
  465.         HUnlock((Handle) this);
  466.     }
  467.     
  468.     /* check to see if we overwrote the cursor */
  469.     
  470.     if ((left <= theColumn) && (right >= theColumn) &&
  471.      (top <= theLine) && (bottom >= theLine) && cursorVis)
  472.          InvertCursor(theColumn, theLine);
  473.     
  474. }
  475.  
  476.  
  477. /*______________________________________________________________________
  478. **
  479. ** InvalCharRect (protected method)
  480. **
  481. **    Invalidate a section of the pane based on the character coordinates
  482. **    provided. Upper left corner is (0,0).
  483. **
  484. **        left (short):        left edge of character rectangle
  485. **        top (short):        top edge
  486. **        right (short):        right edge, inclusive
  487. **        bottom (short):        bottom edge, inclusive
  488. **
  489. */
  490.  
  491. void CTerminalPane::InvalCharRect (short left, short top, short right, short bottom)
  492.  
  493. {
  494.     LongRect    theLongRect;
  495.     
  496.     CalcCharRect(left, top, right, bottom, &theLongRect);
  497.     Prepare();
  498.     RefreshLongRect(&theLongRect);
  499. }
  500.  
  501.  
  502. /*______________________________________________________________________
  503. **
  504. ** InvertCursor
  505. **
  506. **    Invert a single character.
  507. **
  508. **        col (short):    the column number
  509. **        line (short):    the line number
  510. **
  511. */
  512.  
  513. void CTerminalPane::InvertCursor (short col, short line)
  514.  
  515. {
  516.     LongRect    theLongRect;
  517.     Rect        theRect;
  518.     
  519.     CalcCharRect(col, line, col, line, &theLongRect);
  520.     LongToQDRect(&theLongRect, &theRect);
  521.     InvertRect(&theRect);
  522.     if (gGopher != this) {
  523.         InsetRect(&theRect, 1, 1);
  524.         InvertRect(&theRect);
  525.     }
  526. }
  527.  
  528.  
  529. /*______________________________________________________________________
  530. **
  531. ** ScrollTerm
  532. **
  533. **    Push everything on screen up one line.
  534. **
  535. */
  536.  
  537. void CTerminalPane::ScrollTerm (void)
  538.  
  539. {
  540.     BlockMove(&theScreen[1][0], &theScreen[0][0], (maxY-1) * maxX);
  541.     ClearToEOL(0, maxY-1);
  542.     Refresh();
  543. }
  544.  
  545.  
  546. /*______________________________________________________________________
  547. **
  548. ** ScrollToSelection
  549. **
  550. **    Ensure that the current cursor location is visible.
  551. **
  552. */
  553.  
  554. void CTerminalPane::ScrollToSelection (void)
  555.  
  556. {
  557.     LongRect    theVisRect;
  558.     LongRect    theCharRect;
  559.     LongRect    tempRect;
  560.     LongPt    whereTo;
  561.     Boolean    needsScroll = FALSE;
  562.     
  563.     /* figure out panorama coordinates of what’s visible...
  564.         this SHOULD be easier (hint, hint, Symantec) */
  565.     
  566.     GetPosition(&whereTo);
  567.     GetBounds(&tempRect);
  568.     if (!(PtInLongRect(&whereTo, &tempRect))) {
  569.         whereTo.h = 0;                        /* scroll position is just plain bonkers */
  570.         whereTo.v = 0;
  571.         needsScroll = TRUE;
  572.     }
  573.     
  574.     GetAperture(&tempRect);
  575.     theVisRect.left = whereTo.h;
  576.     theVisRect.top = whereTo.v;
  577.     theVisRect.right = whereTo.h + (tempRect.right - tempRect.left);
  578.     theVisRect.bottom = whereTo.v + (tempRect.bottom - tempRect.top);
  579.     
  580.     /* figure out where our cursor is */
  581.     
  582.     CalcCharRect(theColumn, theLine, theColumn, theLine, &theCharRect);
  583.     theCharRect.left -= offsetX;
  584.     theCharRect.top -= offsetY;
  585.     theCharRect.right += offsetX;
  586.     theCharRect.bottom += offsetY;
  587.  
  588.     /* scroll if necessary */
  589.  
  590.     if (theCharRect.bottom > theVisRect.bottom) {
  591.         whereTo.v = Max(theCharRect.bottom, theVisRect.bottom) -
  592.                         (theVisRect.bottom - theVisRect.top);
  593.         needsScroll = TRUE;
  594.     }
  595.     if (theCharRect.top < theVisRect.top) {
  596.         whereTo.v = Min(Min(theCharRect.top, theVisRect.top), 0);
  597.         needsScroll = TRUE;
  598.     }
  599.  
  600.     if (theCharRect.right > theVisRect.right) {
  601.         whereTo.h = Max(theCharRect.right, theVisRect.right) -
  602.                         (theVisRect.right - theVisRect.left);
  603.         needsScroll = TRUE;
  604.     }
  605.     if (theCharRect.left < theVisRect.left) {
  606.         whereTo.h = Min(Min(theCharRect.left, theVisRect.left), 0);
  607.         needsScroll = TRUE;
  608.     }
  609.  
  610.     if (needsScroll) {
  611.         ScrollTo(&whereTo, FALSE);
  612.         Refresh();
  613.     }
  614. }
  615.  
  616.  
  617. /*______________________________________________________________________
  618. **
  619. ** SetBlinking
  620. **
  621. **    Turns on or off cursor blinking.
  622. **
  623. **        blinkMode (Boolean):        TRUE to enable cursor blinking
  624. **
  625. */
  626.  
  627. void CTerminalPane::SetBlinking (Boolean blinkMode)
  628.  
  629. {
  630.     blinkCursor = blinkMode;
  631.     if ((blinkMode)    && (gGopher == this)) {
  632.         lastCursorCol = theColumn;
  633.         lastCursorLine = theLine;
  634.         CursorMoved();
  635.     }
  636.     else {
  637.         cursorVis = TRUE;
  638.         InvalCharRect(theColumn, theLine, theColumn, theLine);
  639.     }
  640. }
  641.